Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support
Apple IIGS
#35:    Printer Driver Specifications

Revised by:    Matt Deatherage & Suki Lee                          March 1989
Written by:    Dan Hitchens                                          May 1988

This Technical Note describes the routines and internal structures needed to 
design a printer driver for the Apple IIGS system and you should reference it 
in conjunction with the Apple IIGS Toolbox Reference manuals.  An overview and 
associated parameters for each of the printer driver routines are in the Print 
Manager chapter, and you should reference these for a complete picture.
Changes since January 1989:  Corrected an error and clarified the section 
on immediate mode procedures.
_____________________________________________________________________________


Printing Modes

There are two printing modes:  immediate and deferred.

o    Immediate mode (also known as draft mode), uses the technique of 
     printing immediately.  As you make QuickDraw II calls, you 
     immediately generate commands which cause printing to occur.  This 
     mode is the fastest form of printing, but it can only print 
     characters in the printer's native mode.  (However, the 
     LaserWriter translates the QuickDraw II calls into PostScript 
     calls which can produce high-quality pixelmap images.)

o    Deferred mode (sometimes referred to as spooling), uses the 
     technique of capturing the QuickDraw II calls for each page in a 
     picture file and plays them back at a later time.  To produce 
     high-quality pixelmap images, you must use deferred mode because 
     of the memory constraint of not being able to draw a complete page 
     in memory at one time.  Due to this limitation, we draw a band (a 
     partial page) at a time.  We create a GrafPort which corresponds 
     to the band and play the picture file back, thus causing the saved 
     commands to draw only the images which fall within the band.  Once 
     the pixel image for the band is generated, we can send it to the 
     printer one pixel at a time.


File Structure

The user can install new printer drivers into the system by copying a printer 
driver file into a subdirectory called DRIVERS within the SYSTEM subdirectory.  
The printer driver file must be of type $BB and have an auxiliary type of 
$0001.


Print Driver Calls

A printer driver must support the following calls:

    PrDefault        $0913    Sets print record to default
    PrValidate       $0A13    Validates print record
    PrStlDialog      $0B13    Performs a style dialog
    PrJobDialog      $0C13    Performs a job dialog
    PrPixelMap       $0D13    Prints a pixelmap
    PrOpenDoc        $0E13    Opens the document
    PrCloseDoc       $0F13    Closes the document
    PrOpenPage       $1013    Opens a page
    PrClosePage      $1113    Closes a page
    PrPicFile        $1213    Prints a picture file
    --RESERVED--     $1313
    PrError          $1413    Gets the error value
    PrSetError       $1513    Sets the error value
    GetDeviceName    $1713    Gets device's name
    PrDriverVer      $2313    Gets installed driver version


Print Driver Entry

o    Entry to the driver is at the first byte (no offset).
o    The contents of the x register is calculated beforehand for use as an 
     index to the correct routine (see the example below and note the specific 
     ordering of the routines).
o    There are two long return addresses (six bytes) that have been pushed 
     onto the stack.  (You must take these addresses into account to access the 
     parameters and to return correctly.)

Example

StartOfDriver    START

                 jmp (PrDriverList,x)

PrDriverList     dc a4'PrDefault'
                 dc a4'PrValidate'
                 dc a4'PrStlDialog'
                 dc a4'PrJobDialog'
                 dc a4'PrPixelMap'
                 dc a4'PrOpenDoc'
                 dc a4'PrCloseDoc'
                 dc a4'PrOpenPage'
                 dc a4'PrClosePage'
                 dc a4'PrPicFile'
                 dc a4'InvalidRoutine'
                 dc a4'PrError'
                 dc a4'PrSetError'
                 dc a4'GetDeviceName'
                 dc a4'PrDriverVer'


Print Driver Exit

You should adjust the stack to use RTL instructions followed by any return 
parameters with the two long return addresses.  To accomplish this, you will 
need to do the following:

o    Eliminate any parameters from the stack which have been passed.
o    Move the long return addresses so that they are before the space for the 
     returned parameters (if any).

Example

The following diagrams the stack just before leaving the print driver:

     | Previous Contents
     +---------------------
     | Results (if any)
     +---------------------
     | RTL2 (3 bytes)
     +---------------------
     | RTL1 (3 bytes)
     +---------------------
                           <--- Stack Pointer

You should do an RTL with the contents of the flags and registers set 
appropriately.  (See the Return from Call section of the "Using The Apple 
Tools" chapter of the Apple IIGS Toolbox Reference.)


Print Record Structure

Since application programs often need to fiddle with parts of the print record 
(i.e., the values in the style subrecord), we have defined ways for 
applications to interpret the print record, and specifically the style 
subrecord.

iDev, the first word of the printer information subrecord, has two defined 
values for third-party printer drivers.  A value of $8001 indicates a dot-
matrix printer while a value of $8003 indicates a laser printer.

A value of $8001 indicates that fields of the style subrecord should be 
interpreted as they are by the ImageWriter driver, as documented in the Apple 
IIGS Toolbox Reference.  The first seven bits (0-6) of wDev are defined as for 
the ImageWriter driver.  Bits 7-11 are reserved for Apple's use and must be 
set to zero.  Bits 12-15 may be used by third-party printer drivers as 
necessary; these bits will be set to zero in Apple's drivers.

A value of $8003 indicates that fields of the style subrecord should be 
interpreted as they are by the LaserWriter driver.  The first four bits (0-3) 
of wDev are defined as for the LaserWriter driver.  Bits 4-11 are reserved for 
Apple's use and must be set to zero.  Bits 12-15 may be used by third-party 
printer drivers as necessary; these bits will be set to zero in Apple's 
drivers.

If an application wishes to take advantages of specific features of a third-
party printer driver, it has to know that it is dealing with that driver.  
Since all drivers will look pretty much alike, the Print Manager allows you to 
ask for the name of the currently selected printer driver.  An application may 
make the Print Manager call PMGetPrinterName, which is documented in this 
Technical Note.  The Print Manager will return the name of the currently 
selected printer in a Pascal (length byte) string.  The name returned is the 
name of the file from which the driver was loaded.  If you intend to use this 
method to identify a driver, you must inform users not to rename the Printer 
Driver file on the boot disk.

The PMGetPrinterName call is as follows:

Note:    This is a Print Manager call, not a Printer Driver call.  It 
         is the only Print Manager call documented in this Note.  Printer 
         Drivers do not include this call.

PMGetPrinterName         ($2813)

Description:
    Returns a Pascal string with the file name of the currently selected 
    printer driver.

Passed:
    Longspace            LONG        Space for result

Returned:
    NamePointer          LONG        Pointer to a Pascal string of driver filename


Print Driver Calls

PrDefault                ($0913)

Description:
    Fills the fields of the specified print record with default values for the 
    printer.

Passed:
    PrintRecordHandle    LONG        Handle to the print record

Returned:
    None

Performs the following:
o    Validates that PrintRecordHandle is a handle and does nothing if not.
o    Determines the default values for the print record either through tables 
     or calculations.  The default values should take into account such things 
     as paper size and orientation, print mode, printer type, etc.
o    Copies the default values to the print record specified by the 
     PrintRecordHandle parameter.


PrValidate               ($0A13)

Description:
    Checks the print record to see that it is valid for the currently 
    installed printer driver.

Passed:
    PrintRecordHandle    LONG        Handle to the print record

Returned:
    ChangeFlag           WORD        Boolean; TRUE if the record is adjusted

Performs the following:
o    Checks to see if the print record is from this particular driver.
o    If the print record is not from this driver, it uses the default values 
     for this driver.
o    If the print record is from this driver, it makes any changes that might 
     be needed (i.e., style, paper size, etc.).


PrStlDialog              ($0B13)

Description:
    Performs a style dialog with the user.

Passed:
    PrintRecordHandle    LONG        Handle to the print record

Returned:
    ConfirmFlag          WORD        Boolean; TRUE if the dialog is confirmed

Performs the following:
o    Conducts a style dialog with the user to determine the page dimensions 
     and other information needed for page setup (the initial settings of the 
     dialog are derived from the print record).
o    If the user confirms the dialog, the information from the dialog is saved 
     in the specified print record, PrValidate is called, and the routine 
     returns TRUE.
o    If the user cancels the dialog, the print record is left unchanged, and 
     the routine returns FALSE.

Note:    The following are items typically found in printer style dialogs:

o    Paper Size (US Letter, US Legal, A4 Letter, B5 Letter, International 
     Fanfold)
o    Printing Orientation (Landscape, Portrait)
o    Vertical Sizing (Normal, Intermediate, Condensed)
o    Special Effects:
        Font Effects (Font Substitution, Smoothing)
        Reduction or Enlargement
        Gaps or No Gaps between pages

Every printer style dialog should have an OK button (default) and a Cancel 
button.


PrJobDialog              ($0C13)

Description:
    Performs a job dialog with the user.

Passed:
    PrintRecordHandle    LONG        Handle to the print record

Returned:
    ConfirmFlag          WORD        Boolean; True if the dialog is confirmed

Performs the following:
o    Conducts a job dialog with the user to determine the print quality, range 
     of pages to print, and other specifications.  The initial settings are 
     derived from the previous PrJobDialog call (or initial default values) 
     except the page range which is set to ALL, and the number of copies which 
     is set to ONE.
o    If the user confirms the dialog, PrValidate is called, the print record 
     is updated, and the routine returns TRUE.
o    If the user cancels the dialog, the print record is left unchanged, and 
     the routine returns FALSE.

Note:    The following are items typically found in printer job dialogs:

o    Print Quality (Best, Faster, Draft, etc.)
o    Color option
o    Pages (All, Range)
o    Copies
o    Paper Source (paper cassette, manual feed)

Every printer job dialog should have an OK button (default) and a Cancel 
button.


PrPixelMap               ($0D13)

Description:
    Prints all or part of the specified pixelmap.

Passed:
    srcLocPtr            LONG        Pointer to the source LocInfo which
                                     contains the pointer to the pixelmap.
    srcRectPtr           LONG        Pointer to the rectangle which
                                     encloses the pixelmap to be printed.
    colorFlag            WORD        Boolean; FALSE if black and white,
                                     TRUE if color.

Returned:
    None

Performs the following:
o    Calls DevIsItSafe (port driver call) to verify that the port it 
     functioning and it is safe to proceed.  If it is not functioning, set the 
     internal error code to $1302 (Port Not On) and return with an error status.
o    Saves the current port.
o    Turns on the watch cursor to signal the user that it will take some time.
o    Clears the internal error code (default, if no errors occur).
o    Gets a new handle for a print record and set it to the defaults by 
     calling PrDefault.
o    If colorFlag is set, sets bit 5 of wdev in prStl of the print record.
o    Do any initialization that might be needed by the driver.
o    Determine the intersection of the two rectangles (rectangle pointed to by 
     srcRectPtr and the pixelmap's boundary rectangle from srcLocPtr) and if 
     there is no intersection, then nothing is to be printed.
o    Print the pixel image which is within the intersection of the two 
     rectangles.
o    Cause a page eject to occur on the printer.
o    Do any clean up that is needed.
o    Turn off the watch cursor by calling InitCursor.
o    Restore the port by calling SetPort.


PrOpenDoc                ($0E13)

Description:
    This routine initializes the things needed to open a document.  In 
    deferred mode, it establishes a GrafPort and makes it the current port for 
    printing.

Passed:
    PrintRecordHandle    LONG        Handle to the print record
    PrinterPortPtr       LONG        Pointer to the GrafPort, if desired,
                                     zero to allocate a new GrafPort
Returned:
    PrinterPortPtrRet    LONG        Pointer to the GrafPort if the
                                     PrinterPortPtr was zero

Performs the following:
o    Calls DevIsItSafe (port driver call) to verify that the port is 
     functioning and it is safe to proceed.
o    Turns on the watch cursor to signal the user that it will take some time.
o    Validates the print record passed by  calling PrValidate.
o    Clears the internal error code (default, if nothing happens).
o    Puts up a dialog indicating that printing is occurring (or preparing to 
     print).
o    If the user needs a GrafPort, create one and internally note that one was 
     created (PrCloseDoc will need to know that one was created here).
o    Initializes parameters (i.e., page number, document number, etc.).
o    If deferred mode, create an initial page list (an array of handles to 
     pictures) for 20 pages (arbitrary number to start).
o    Do other initialization that might be needed to start a print job.

Possible errors:
                         $1302       Indicates Port Not On


PrCloseDoc               ($0F13)

Description:
    Closes the GrafPort being used for printing.  For immediate mode, this 
    routine ends the printing job.  For deferred mode, this routine ends the 
    process allowing the job to be printed.

Passed:
    PrintGrafPortPtr     LONG        Pointer to the GrafPort used for printing

Returned:
    None

Performs the following:
o    Checks that the last print driver call did not cause a Port Not On error.  
     If the error occurred, do nothing and return.
o    Call ClosePort (port driver call) to close the port.
o    If the driver allocated a GrafPort in PrOpenDoc, dispose of it.
o    If in immediate mode, do what is needed to shut things down.
o    Takes down the information dialog box from PrOpenDoc.


PrOpenPage               ($1013)

Description:
    Begins a new page only if the page falls within the page range specified 
    in the job subrecord.

Passed:
    PrintGrafPortPtr     LONG        Pointer to the GrafPort used for printing
    PageFramePtr         LONG        Pointer to the scaling parameter,
                                     zero for none.
Returned:
    None

Performs the following:
o    Looks at the driver's internal error value, and if an error has occurred, 
     it returns without doing anything.
o    Increments the page number.
o    Calls SetPort to make the specified port the current port.
o    Initializes the port and zeroes the boundary rectangle so no actual 
     drawing will occur.
o    If immediate mode, then do the following:
        If this page is to be printed, install immediate mode procedures by 
        doing the following:
        o    Create a procedure table (get the standard procedures. from 
             SetStdProcs).
        o    Put pointers to your procedures into the table and call the 
             QuickDraw II routine SetGrafProcs.  This will cause QuickDraw II 
             calls to print instead of writing to the GrafPort.
o    If deferred mode, then do the following:
        o    If the current page is out of the page range, then return without 
             doing anything further.
        o    If the user passes his own PageFramePtr , then get it.
        o    Open a picture by calling OpenPicture and adding its handle to the 
             page list array described in PrOpenDoc.
        o    Set the ClipRgn and VisRgn to the sizing framing rectangle 
             specified by PageFramePtr, or if none was specified, to the default 
             of rPage.


PrClosePage              ($1113)

Description:
    This signals the end of a page.

Passed:
    PrintGrafPortPtr     LONG        Pointer to the GrafPort used for printing

Returned:
    None

Performs the following:
o    Looks at the driver's internal error value and if a Port Not On error has 
     occurred, it returns without doing anything.
o    If immediate mode, do the following:
o    If the current page is within the range of pages to be printed, then 
     cause a form feed (unless no gap was specified).
o    If deferred mode, do the following:
o    If there was no picture generated, then do nothing and just return.
o    Call SetPort to make the specified port the current port.
o    Do a ClosePicture to close the picture.


PrPicFile                ($1213)

Description:
    Prints a picture file generated in deferred mode.

Passed:
    PrintRecordHandle    LONG        Handle to the print record
    PrintGrafPortPtr     LONG        Pointer to the GrafPort used for printing
    StatusRecPtr         LONG        Pointer to the printer status record

Returned:
    None

Performs the following:
o    Looks at the driver's internal error value and if a Port Not On error has 
     occurred, it returns without doing anything.
o    If immediate mode, return without doing anything.
o    If deferred mode, then do the following:
     o    If the error code is not zero (errors) then dispose of everything.
     o    Put up an information dialog indicating that printing is occurring.
     o    If PrintGrafPortPtr is NIL, create one and make a note of it.
     o    Call OpenPort to make the GrafPort the current port.
     o    If StatusRecPtr is NIL, use an internal one.
     o    Initialize the status record and the number of copies counter.
     o    If the idle proc in the print record is NIL, point to an internal one.
     o    Do The Following For Each Copy:
          o    Calculate the number of bands it will take to print one page and 
               initialize the page counter.
          o    Do The Following For Each Page:
               o    Call the idle procedure routine and initialize the band 
                    counter.
               o    Get the handle to the picture associated with the current 
                    page.
               o    Set the dirty flag in the status record to FALSE.
               o    If manual paper feed, put up a dialog and wait for a response.
               o    Do The Following For Each Band:
                    o    Call the idle procedure.
                    o    Calculate the band rectangle and update icurband with the 
                         current band number.
                    o    Call the idle proc again.
                    o    Set the imaging flag in the status record to TRUE.
                    o    Call InitPort to reinitialize the port.
                    o    Adjust fields in the port to cause drawing into the band 
                         buffer.
                    o    Adjust fields in the location information field of the 
                         status record and calculate the sizing rectangle.
                    o    Calculate the boundary rectangle for the band and set the 
                         port rectangle to it.
                    o    Set the ClipRgn and the VisRgn to the sizing rectangle.
                    o    Initialize the band by filling it with white space.
                    o    Call DrawPicture to draw the picture into the band's 
                         rectangle.
                    o    Do whatever is needed to print the pixel image in the 
                         band's rectangle.
                    o    Clear the imaging flag.
                    o    Calculate the next band's position.
                    o    Increment the band's counter and loop back if not done.
               o    If GAP was specified, cause a form feed.
               o    Increment the page count to the next page and loop back if not 
                    done.
          o    Increment the number of copies counter and loop back if not done.
     o    Free any buffers that you own and close the port.
     o    Dispose of the information dialog that you put up.
     o    Dispose of each picture in the picture list by calling KillPicture.
     o    Dispose of the picture list itself.
     o    Reset the cursor.

     
PrError                  ($1413)

Description:
    Gets the error code from the last Print Manager call.

Passed:
    None

Returned:
    LastError            WORD        Result code from last Print Manager call

Performs the following:
o    Gets the driver's internal error value (which was determined by the last 
     driver call) and sets the return parameter LastError to it.

Possible Errors:
noError                  $0000
PrAbort                  $0080       Indicates print job was aborted
                         $1301       Indicates missing drivers
                         $1302       Indicates Port Not On
                         $1303       Indicates No Print Record
                         $1306       Indicates PAP Connection Not Made
                         $1307       Indicates Read/Write PAP Error
                         $1308       Indicates Printer Connection Failed


PrSetError               ($1513)

Description:
    Sets the error value.

Passed:
    ErrorNumber          WORD        Error number to be set

Returned:
    None

Performs the following:
o    Sets the driver's internal error value to the value of the passed 
     ErrorNumber parameter.


GetDeviceName            ($1713)

Description:
    This is used as a communications tool between the printer driver and port 
    driver.

Passed:
    None

Returned:
    None

Performs the following:
o    Calls the port driver routine PrDevPrChanged with the printer name as 
     input.  This is necessary for drivers that will work over AppleTalk.  The 
     name passed as the parameter to PrDevPrChanged should be what AppleTalk 
     will use in an NBPLookup situation.


PrDriverVer              ($2313)

Description:
    Returns the version number of the currently installed printer driver.

Passed:
    Wordspace            WORD        Space for results

Returned:
    versionInfo          WORD        Printer driver's version number

Performs the following:
o    Gets the internal version number of the printer driver and returns it on 
     the stack at versionInfo.

Note:    The internal version number is stored major byte, minor byte
         (i.e., $0103 represents version 1.3)


Immediate Mode Procedures

To print in the immediate mode, you need to install procedures which will 
cause printing when you make QuickDraw II calls (as noted in PrOpenPage).  
This section describes the structure and parameters for these routines.

To install the immediate mode procedures, first create a procedure table for 
sixteen entries (16*4 bytes) and fill it with the standard procedures by 
calling SetStdProcs.  Once you have the standard procedures, install the 
addresses of your procedures into it and call SetGrafProcs.  Installing your 
procedure addresses will cause the appropriate QuickDraw II calls to call your 
procedures, which, in turn, will perform the actual printing.

The routines that need to be written are known as QuickDraw II "bottleneck 
procedures."  Access to the routines are from bank $E0 (accessed by doing a 
JSL to the appropriate address in bank $E0).  When you call any of the 
bottleneck procedures, the first direct page of QuickDraw II is active and the 
following direct page locations are valid:

    PortRef      $24
    MaxWidth     $20
    MasterSCB    $08
    UserId       $0A

Two bottleneck procedures, StdText and StdPixels, are of most concern when 
writing immediate mode procedures.  (Refer to Apple IIGS Technical Note #34 
for more information on bottleneck procedures.)

The routine StdText (standard text) is the standard text drawing routine.  To 
install this routine into your procedure table (as described above), make it 
the first entry (offset of $00).  Once it's installed, you can access it by 
doing a long call to absolute address $E01E04.  Its direct page parameters are 
as follows:

    DrawVerb      $38    Describes the kind of text to draw.  There 
                         are three possible values:
                             DrawCharVerb    0
                             DrawTextVerb    1
                             DrawCStrVerb    2
    TextPtr       $DA    If the draw verb is DrawTextVerb or 
                         DrawCStrVerb, TextPtr points to the text 
                         buffer or C string to draw.
    TextLength    $D8    If the draw verb is DrawTextVerb, 
                         TextLength contains the number of bytes in 
                         the text buffer.
    CharToDraw    $D6    If the draw verb is DrawCharVerb, 
                         CharToDraw contains the character to draw.

The routine StdPixels is the standard pixelmap drawing routine.  To install 
this routine into your procedure table (as described above), put it at offset 
$20.  Once it's installed, you can access it by doing a long call to absolute 
address $E01E24.  Its direct page parameters are as follows:

    SrcLocInfo    $CC    The LocInfo record for the source pixel 
                         map
    DestLocInfo   $0C    The LocInfo record for the destination 
                         pixel map
    SrcRect       $DC    The source rectangle for the operation in 
                         local coordinates for the source pixel map 
                         (as described in the source LocInfo 
                         record)
    DestRect      $1C    The destination rectangle for the 
                         operation in local coordinates for the 
                         destination pixel map (as described in the 
                         destination  LocInfo record)
    XferMode      $E4    The mode to use for data transfer
    RgnHandleA    $50    The handle to the first region to which 
                         drawing is clipped (usually the ClipRgn 
                         from the GrafPort)  A NIL handle is not 
                         allowed.  To signify no clipping, pass a 
                         handle to the WideOpen region, which is 
                         defined as 10 bytes:

                         Length      $A       (word)
                         -MaxInt    -$3FFF    (word)
                         -MaxInt    -$3FFF    (word)
                         +MaxInt    +$3FFF    (word)
                         +MaxInt    +$3FFF    (word)

    RgnHandleB    $60    The handle to the second region to which 
                         drawing is clipped (usually the VisRgn 
                         from the GrafPort)  A NIL handle is not 
                         allowed.  To signify no clipping, pass a 
                         handle to the WideOpen region.
    RgnHandleC    $70    The handle to the second region to which 
                         drawing is clipped (usually the mask 
                         region from the CopyPixels or the 
                         PaintPixels call)  A NIL handle is not 
                         allowed.  To signify no clipping, pass a 
                         handle to the WideOpen region.


Example:

;*****************************************************************
;** Example of Immediate Mode Printer Procedures.               **
;*****************************************************************

Immedprocs    Start

SrcRect       equ $DC
SrcLocInfo    equ $CC
DrawVerb      equ $38
TextPtr       equ $da
TextLength    equ $d8
CharToDraw    equ $d6

;------------------------------------------------------------------
;
; _StdPixels Procedure (Prints Pixelmaps)
;
;------------------------------------------------------------------
Pixel         Entry

              phb                  ;save data bank reg on stack
              phk                  ;get program bank reg.
              plb                  ;use as data bank reg.

              lda iPrErr           ;get errors
              beq Continue         ;branch if none
              brl ExitPixel        ;branch if errors

Continue      anop
;This gets the source rectangle and stores it at PixelRect
              ldx #6
MoveSrc       lda SrcRect,x
              sta PixelRect,x
              dex
              dex
              bpl MoveSrc

;This gets the source LocInfo and stores it at PixelLoc 
              ldx #16-2
MoveLI        lda SrcLocInfo,x
              sta PixelLoc,x
              dex
              dex
              bpl MoveLI

              pushptr PixelLoc     ;push pointer to LocInfo
              pushptr PixelRect    ;push pointer to rectangle

;++++++++++++++++++++++
; Insert code here to print a pixelmap
;    INPUT:    PixelLoc     LONG, Pointer to pixel LocInfo
;              PixelRect    LONG, Pointer to pixels BoundsRect
;           SP->
;++++++++++++++++++++++

Exitpixel     lda #0               ;return with no errors
              clc
              plb                  ;restore data bank
              rtl                  ;returnith long
    
PixelLoc      ds 16                ;pixel LocInfo
PixelRect     ds 8                 ;pixel rectangle


;------------------------------------------------------------------
;
; _StdText Procedure (Prints Standard Text)
;
;------------------------------------------------------------------
StdText       Entry

              phb                  ;save data bank reg on stack
              phk                  ;get program bank reg. 
              plb                  ;use as data bank reg.

              pushptr PenPos
              _GetPen              ;current pen pos. -> PenPos

;++++++++++++++++++++++
; Insert Code Here to move the printers head to the corresponding
; PenPos position (if needed).
;++++++++++++++++++++++

              pushword #0          ;space for textwidth
                                   ;(for call to _TextWidth)

              lda DrawVerb         ;get DrawVerb
              beq DoCar            ;if DrawVerb=0 then DoCar

              cmp #1
              beq Dotext2          ;if DrawVerb=1 then Dotext2
;
;We get here if it's a "C" string (DrawVerb=2)
;
DoCstring     anop
              sep #$20
              longa off
;Search down through string looking for terminator to calc. length
              ldy #0
KeepLooking   lda [TextPtr],y
              beq TheEnd
              iny
              bra KeepLooking
TheEnd        rep #$20
              longa on
              lda TextPtr+2
              pha                  ;push the pointer to string
              lda Textptr
              pha
              phy                  ;push the length of sting
              bra Common
;
;We get here if it's just one character (DrawVerb=0)
;
DoCar         anop
              pushword #0
              tdc
              clc
              adc #CharToDraw      ;calculate addr. of char.
              pha                  ;push addr. of character
              pushword #1          ;push length of one char.
              bra Common
;
;We get here if it's a string of text (DrawVerb=1)
;
DoText2       anop
              lda TextPtr+2
              pha                  ;push pointer to the string
              lda Textptr
              pha
              lda TextLength
              pha                  ;push the strings length
Common        lda 5,s              ;Dup the last 3 words of
              pha                  ;the stack (for _TextWidth)
              lda 5,s
              pha
              lda 5,s
              pha
;++++++++++++++++++++++
; Insert code here to print the text
;
;    INPUT:    TextPointer    LONG, Pointer to text to print
;              TextLength     WORD, No. of bytes to print
;          SP->
;++++++++++++++++++++++
              _TextWidth           ;get the texts width (DH)
              pushword #0          ;set (DV)=0
              _Move                ;move current pen location

ExitText      lda #0               ;return with no errors
              clc
              plb                  ;restore data bank
              rtl                  ;returnith long

PenPos        ds 4                 ;pen position
              end


Further Reference
_____________________________________________________________________________
    o    Apple IIGS Toolbox Reference, Volumes 1 & 2